/*
 * Author: 李波(Edwin Lee)
 * Date: 2024-08-15 16:37:12
 * FilePath: /mprpc/src/mprpcchannel.cc
 * LastEditTime: 2024-09-03 12:59:19
 * version: 1.0
 * Description: 
 */
#include "mprpcapplication.h"
#include "rpcheader.pb.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/service.h"
#include "logger.h"
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <unistd.h>
#include <zookeeperutil.h>

void MprpcChannel::CallMethod(const google::protobuf::MethodDescriptor *method,
                              google::protobuf::RpcController *controller, 
                              const google::protobuf::Message *request,
                              google::protobuf::Message *response, 
                              google::protobuf::Closure *done)
{

    const google::protobuf::ServiceDescriptor* sd = method->service();
    std::string service_name = sd->name();
    std::string method_name = method->name();

    // 获取参数序列化字符串长度 
    uint32_t args_size = 0;
    std::string args_str;
    if(!request->SerializeToString(&args_str))
    {
        controller->SetFailed("request serialize failed!");
        return;
    }
    args_size = args_str.size();
    // 定义rpc的请求header
    mprpc::RpcHeader rpcHeader;
    rpcHeader.set_service_name(service_name);
    rpcHeader.set_method_name(method_name);
    rpcHeader.set_args_size(args_size);

    std::string rpc_header_str;
    if(!rpcHeader.SerializeToString(&rpc_header_str))
    {
        //std::cout << "rpcHeader serialize failed!" << std::endl; 该为使用controller保存错误信息
        controller->SetFailed("rpcHeader.SerializeToString failed!");
        return;
    }
    uint32_t header_size = rpc_header_str.size();
    // 组织待发送的rpc请求的字符串
    std::string send_rpc_str((char*)&header_size,4);
    send_rpc_str += rpc_header_str;
    send_rpc_str += args_str;

    // tcp编程
    int clientfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == clientfd)
    {
        //std::cout << "socket failed! errno: " << errno <<std::endl;
        std::string errStr("socket failed! errno: ");
        errStr += std::to_string(errno);
        controller->SetFailed(errStr);
        return;
    }

    // 读取配置文件rpcserver的信息
    // std::string ip = MprpcApplication::getInstance().getConfig().load("rpcserverip");
    // uint16_t port = atoi(MprpcApplication::getInstance().getConfig().load("rpcserverport").c_str());
    ZkClient zkcli;
    zkcli.start();
    // /UserServiceRpc/Login
    std::string method_path = "/" + service_name + "/" + method_name;
    // 127.0.0.1:8000
    std::string host_data = zkcli.getData(method_path.c_str());
    if(host_data == "")
    {
        controller->SetFailed(method_path + "is not exit!");
        return;
    }
    int idx = host_data.find(":");
    if (idx == -1)
    {
        controller->SetFailed(method_path + "zk address is invalid!");
        return;
    }
    std::string ip = host_data.substr(0, idx);
    uint16_t port = atoi(host_data.substr(idx+1, host_data.size()-idx).c_str()); 
    //客户端网络编程
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    //inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr.s_addr);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    if(0 != connect(clientfd,(struct sockaddr*)&addr,sizeof(addr)))
    {
        //std::cout << "connect to " << ip << " :" << port << " failed!" << std::endl;
        std::string errStr("connect to ");
        errStr = errStr + "connec to " + ip + " :" + std::to_string(port) + " failed!";
        controller->SetFailed(errStr);
        close(clientfd);
        return;
    }

    if(-1 == send(clientfd, send_rpc_str.c_str(),send_rpc_str.size(),0))
    {
        std::string errStr("send failed! errno: ");
        errStr += std::to_string(errno);
        close(clientfd);
        return;
    }

    char recv_buf[1500]{0};
    int recv_size = 0;
    if(-1 == (recv_size = recv(clientfd,recv_buf,sizeof recv_buf,0)))
    {
        std::string errStr("recv error! errno: ");
        errStr += std::to_string(errno);
        controller->SetFailed(errStr);
        close(clientfd);
        return;
    }
    // 反序列化调用的结果
    if(!response->ParseFromArray(recv_buf,recv_size))
    {
        std::string errStr("parse error! recv_buf: ");
        errStr += recv_buf;
        controller->SetFailed(errStr);
        close(clientfd);
        return;
    }
    //LOG_INFO("response : %s",response->GetReflection()->GetString().c_str());
    close(clientfd);
}
